package org.spring.aicloud.util.idempotent;

import cn.hutool.crypto.SecureUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.spring.aicloud.entity.detail.SecurityUserDetails;
import org.spring.aicloud.util.SecurityUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 *  幂等性判断的拦截器
 * @author chenchang
 */
@Component
public class IdempotentInterceptor implements HandlerInterceptor {
    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //如果不是控制器方法，不用进行幂等性判断
        if (! (handler instanceof HandlerMethod)){
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        //先判断此方法上有没有幂等性注解
        Method method = ((HandlerMethod) handler).getMethod();
        Idempotent idempotent = method.getAnnotation(Idempotent.class);
        //如果方法上没有幂等性注解，那就不用进行幂等性判断
        if (idempotent==null){
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        //进行幂等性判断
        //根据uid和请求体的MD5值生成一个唯一的业务id
        String id = createId(request);
        //然后存储到redis中，如果redis中存在这个业务id，说明请求已经处理过了，就不用处理了
        if (redisTemplate.opsForValue().get(id)!=null){
            //说明当前请求已经处理过了
            response.getWriter().write("{\"code\":\"10001\",\"msg\":\"idempotent\"}");
            return false;

        }else {
            //当前请求没有处理过
            redisTemplate.opsForValue().set(id,"true",idempotent.time(), TimeUnit.SECONDS);
            return true;
        }
    }

    private String createId(HttpServletRequest request) throws JsonProcessingException {
        //先拿到uid
        Long uid  = 0L;
        SecurityUserDetails userDetails  = SecurityUtil.getCurrentUser();
        if (userDetails!=null){
            uid = userDetails.getUid();
        }
        //得到请求体
        String requestParam = objectMapper.writeValueAsString(request.getParameterMap());
        //针对uid和请求体进行md5加密生成唯一的业务id
        return SecureUtil.md5(uid+requestParam);
    }
}
